
export const BLEOptions = {
    filters: [
        { namePrefix: 'PT-51DC' },
        { services: ['e7810a71-73ae-499d-8c15-faa9aef0c3f2'] }
    ],
    //   acceptAllDevices: true,
    optionalServices: ['e7810a71-73ae-499d-8c15-faa9aef0c3f2']
}

export async function getBluetooth() {
    try {
        const device = await navigator.bluetooth.requestDevice(BLEOptions);
        const server = await device.gatt?.connect();
        // server.getPrimaryService('000018f0-0000-1000-8000-00805f9b34fb')
        const service = await server.getPrimaryService('e7810a71-73ae-499d-8c15-faa9aef0c3f2')
        const chara = await service.getCharacteristic('bef8d6c9-9c21-4c9e-b632-bd58c1009f9f')
        return chara
        // const imageData = await getImageData(imageElement,30,30)
    } catch (error) {
        console.log(error)
    }
}

export function getBluetoothP() {
    return new Promise((resolve, reject) => {
        navigator.bluetooth.requestDevice({
            filters: [
                { namePrefix: 'PT-51DC' },
                { services: ['e7810a71-73ae-499d-8c15-faa9aef0c3f2'] }
            ],
            //   acceptAllDevices: true,
            optionalServices: ['e7810a71-73ae-499d-8c15-faa9aef0c3f2']
        }).then((device) => {
            device.gatt?.connect().then((server) => {
                server.getPrimaryService('e7810a71-73ae-499d-8c15-faa9aef0c3f2').then((service) => {
                    service.getCharacteristic('bef8d6c9-9c21-4c9e-b632-bd58c1009f9f').then((chara) => {
                        resolve(chara)
                    })
                })
            })
        })
    })
}

export function bitsToByte(bits: number[]) {
    let result = 0
    for (let i = 0; i < bits.length; i++) {
        result = result << 1
        if (bits[i] > 0) {
            result |= 1
        }
    }
    return result
}

export async function convertBitmapFromImage(image: ImageData) {

    const width = image.width
    const height = image.height

    // check width height can mod by 8
    if (width % 8 !== 0) {
        throw new Error('width must be multiple of 8')
    }

    const bitmap = []
    const dense = 8


    const data = image.data
    const printerBitmap = []

    for (let i = 0; i < data.length; i += 4) {

        const r = data[i]
        const g = data[i + 1]
        const b = data[i + 2]
        const a = data[i + 3]
        // if it is not white push 255 else push 0
        if (r !== 255 || g !== 255 || b !== 255 || a !== 255) {
            bitmap.push(255)
        } else {
            bitmap.push(0)
        }
    }

    for (let i = 0; i < bitmap.length; i += 8) {
        const row = bitmap.slice(i, i + 8)
        printerBitmap.push(bitsToByte(row))
    }

    return {
        bitmap: new Uint8Array(printerBitmap),
        width: width / dense,
        height: height
    }

}


/**
 * 
 * @param imgEl ImageElement
 * @param width Resize width
 * @param height Resize height
 * @returns ImageData
 */
export function getImageData(imgEl: HTMLImageElement, width?: number | undefined, height?: number | undefined) {
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')

    if (!ctx) {
        return
    }

    if (width && height) {
        canvas.width = width
        canvas.height = height
    } else {
        canvas.width = imgEl.width
        canvas.height = imgEl.height
    }
    
    ctx?.drawImage(imgEl, 0, 0, canvas.width, canvas.height)
    const imageData = ctx?.getImageData(0, 0, canvas.width, canvas.height)
    return imageData
}


export function toCommand(bitmap: Uint8Array, width: number, height: number) {
    const cmd: Uint8Array[] = []
    for (let i = 0; i < height; i++) {
        const row = bitmap.slice(i * width, (i + 1) * width)
        let tail = row.length - 1
        for (; tail >= 0; tail--) {
            if (row[tail] !== 0) {
                break
            }
        }
        if (tail < 0) {
            cmd.push(new Uint8Array([0x15, 0x01]))
        } else {
            let index = 0
            const result = new Uint8Array(1 + 1 + tail + 1)
            result[index++] = 0x16
            result[index++] = tail + 1
            for (let j = 0; j <= tail; j++) {
                result[index++] = row[j]
            }
            cmd.push(result)
        }
    }
    return cmd
}


export async function bluetoothPrintImageData(chara: any, imageData: ImageData) {

    try {

        if (!imageData) {
            throw new Error('Fail to get image data')
        }
        const bitmap = await convertBitmapFromImage(imageData)

        const cmd = toCommand(bitmap.bitmap, bitmap.width, bitmap.height)

        const length = cmd.length
        const dataCount = cmd.length

        const fw = bitmap.width
        const bh = bitmap.height
        const usePrint = length

        const D11 = dataCount & 0xff
        const D2 = (dataCount >> 8) & 0xff
        const D3 = (dataCount >> 16) & 0xff
        const D4 = (dataCount >> 24) & 0xff

        const nl = usePrint % 256
        const nh = Math.ceil(usePrint / 256)
        // sleep 1sec
        await new Promise((resolve) => { setTimeout(() => { resolve('') }, 1000); })

        await chara.writeValue(new Uint8Array([
            0x17,
            nl,// nl
            nh,//mh
            0x00,//sl
            0x00, //sh
            fw, //fw
            0x00, //0
            0x01, //label count
            0x01, //label index
            D11, //d11
            D2, //d2
            D3, //d3
            D4, //d4
        ]))

        let send = 1

        let cmdBuff = new Uint8Array([])
        const sendData: Uint8Array[] = []

        await new Promise((resolve) => {
            setTimeout(() => {
                resolve('')
            }, 1000);
        })

        for (let i = 0; i < cmd.length; i++) {
            const d = cmd[i]
            if (send + d.length > 256) {
                sendData.push(new Uint8Array([...cmdBuff]))
                cmdBuff = new Uint8Array([])
                send = 0
            }
            send += d.length
            cmdBuff = new Uint8Array([...cmdBuff, ...d])
        }
        if (cmdBuff.length) {
            sendData.push(new Uint8Array([...cmdBuff]))
        }

        for (let i = 0; i < sendData.length; i++) {
            await chara.writeValue(sendData[i])
        }
        await chara.writeValue(new Uint8Array([0x0c])).then(() => {
            console.log('done')
        })

    } catch (error) {
        console.log(error)

    }
}